import datetime

from django.test import TestCase
from django.test import RequestFactory, TestCase, Client
from django.core.cache import caches

from rest_framework import status

from unittest.mock import MagicMock, patch
from jqgame.basegame import GameType
from jqgame.raffle import quanjushang_raffle
from wxuser.serializers import (
    get_detail_UserPackage,
    calculate_UserPackage_sum_price,
    calculate_UserPackage_sum_price_by_date,
)
from juqiadmin.tests import admin_login
from warehouse.tests import JuqiGoodTest

from juqiadmin.models import JuqiAdmin, get_game_finance

from wxuser.models import Users, UserPackage, UserPackageRecord

from warehouse.models import JuqiGood

from .models import (
    WuxianshangGame,
    WuxianshangGameGood,
    WuxianshangRaffleRecord,
    update_price_WuxianshangGame,
)

from warehouse.serializers import JuqiGoodSerializer

from wxuser.tests import UserTest

import json

from pprint import pprint


# Create your tests here.
class WuxianshangGameTest(TestCase):
    def setUp(self):
        # Every test needs access to the request factory.
        self.c = Client()
        self.factory = RequestFactory()
        self.admin_user = {"user": "admin", "password": "admin123"}
        u = JuqiAdmin(**self.admin_user)
        u.save()

    @classmethod
    def create_a_game(cls) -> WuxianshangGame:
        game = WuxianshangGame(
            **{"name": "zoo", "display_url": "http://zoo", "state": 1}
        )
        game.save()

        _goods = [
            {
                "name": "bee",
                "display_url": "http://bee",
                "price": 100,
                "game_type": "wuxianshang",
            },
            {
                "name": "duck",
                "display_url": "http://duck",
                "price": 9900,
                "game_type": "wuxianshang",
            },
        ]
        weights = {
            "bee": 99,
            "duck": 1,
        }
        goods = []
        for g in _goods:
            good = JuqiGood(**g)
            good.save()
            goods.append(good)

            WuxianshangGameGood(
                **{
                    "game_uuid": game.uuid,
                    "good_uuid": good.uuid,
                    "good_weight": weights[good.name],
                }
            ).save()

        update_price_WuxianshangGame(game)

        return game, goods

    # python .\manage.py test wuxianshang.tests.WuxianshangGameTest.test_query_single_game
    def test_query_single_game(self):
        game, _ = WuxianshangGameTest.create_a_game()
        # login
        r = self.c.post(
            "/api/admin/login",
            self.admin_user,
            content_type="application/json",
        )
        self.assertEqual(r.status_code, status.HTTP_200_OK)

        d = json.loads(r.content)
        self.assertEqual(len(self.c.session.get("login_token", "")), 64)
        self.assertEqual(d["code"], "0")

        # get single good
        r = self.c.get(
            "/api/wuxianshang/game",
            {"name": game.name},
            content_type="application/json",
        )
        self.assertEqual(r.status_code, status.HTTP_200_OK)

        res = json.loads(r.content)
        self.assertEqual(res["name"], game.name)
        self.assertEqual(res["display_url"], game.display_url)
        self.assertEqual(res["price"], 300)

    # python .\manage.py test wuxianshang.tests.WuxianshangGameTest.test_query_many_game
    def test_query_many_game(self):
        game, goods = WuxianshangGameTest.create_a_game()
        # login
        r = self.c.post(
            "/api/admin/login",
            self.admin_user,
            content_type="application/json",
        )
        self.assertEqual(r.status_code, status.HTTP_200_OK)

        d = json.loads(r.content)
        self.assertEqual(len(self.c.session.get("login_token", "")), 64)
        self.assertEqual(d["code"], "0")

        # get single good
        r = self.c.get(
            "/api/wuxianshang/game",
            {"name": game.name, "list": 1, "page": 1, "num": 10},
            content_type="application/json",
        )
        self.assertEqual(r.status_code, status.HTTP_200_OK)

        res = json.loads(r.content)
        self.assertEqual(res[0]["name"], game.name)
        self.assertEqual(res[0]["display_url"], game.display_url)
        self.assertEqual(res[0]["price"], 300)

    # python .\manage.py test wuxianshang.tests.WuxianshangGameTest.test_post_game
    def test_post_game(self):
        # login
        r = self.c.post(
            "/api/admin/login",
            self.admin_user,
            content_type="application/json",
        )
        self.assertEqual(r.status_code, status.HTTP_200_OK)

        d = json.loads(r.content)
        self.assertEqual(len(self.c.session.get("login_token", "")), 64)
        self.assertEqual(d["code"], "0")

        # create good
        goods = [
            {
                "name": "bee",
                "display_url": "http://bee",
                "price": 100,
                "game_type": "wuxianshang",
            },
            {
                "name": "duck",
                "display_url": "http://duck",
                "price": 9900,
                "game_type": "wuxianshang",
            },
        ]

        weights = {
            "bee": 99,
            "duck": 1,
        }

        rarities = {
            "bee": "白银款",
            "duck": "黄金款",
        }

        goods_info = []
        for g in goods:
            r = self.c.post(
                "/api/warehouse/good",
                g,
                content_type="application/json",
            )
            self.assertEqual(r.status_code, status.HTTP_201_CREATED)
            good = json.loads(r.content)
            weight = weights[good["name"]]
            rarity = rarities[good["name"]]
            goods_info.append(
                {
                    "good_uuid": good["uuid"],
                    "good_weight": weight,
                    "good_rarity": rarity,
                }
            )

        # create game
        game = {"name": "zoo", "display_url": "http://zoo"}
        game["goods"] = goods_info
        r = self.c.post(
            "/api/wuxianshang/game",
            game,
            content_type="application/json",
        )
        self.assertEqual(r.status_code, status.HTTP_201_CREATED)

        res = json.loads(r.content)
        print(res)
        self.assertEqual(res["name"], game["name"])
        self.assertEqual(res["display_url"], game["display_url"])
        self.assertEqual(res["price"], 999999)


# python .\manage.py test wuxianshang.tests.WuxianshangRaffleTest
class WuxianshangRaffleTest(TestCase):
    def setUp(self):
        # Every test needs access to the request factory.
        self.wx_c = Client(HTTP_X_WX_OPENID="wx123")

    def test_raffle_bee_use_stored_money(self):
        _ = UserTest.create_a_user()
        game, goods = WuxianshangGameTest.create_a_game()
        bee = JuqiGood.objects.get(name="bee")

        # raffle
        raffle_count = 3

        with patch("wuxianshang.views.wxs_raffle") as _wxs_raffle:
            _wxs_raffle.return_value = {bee.uuid: raffle_count}
            r = self.wx_c.post(
                "/api/wuxianshang/raffle/",
                {
                    "pay_type": "stored_money",
                    "raffle_count": raffle_count,
                    "game_uuid": game.uuid,
                },
                content_type="application/json",
            )
            d = json.loads(r.content)

            self.assertEqual(r.status_code, status.HTTP_200_OK)

            self.assertEqual(len(d["goods"]), raffle_count)

            admin_finance = get_game_finance(GameType.wuxianshang)

            # frash game price
            _game = WuxianshangGame.objects.get(uuid=game.uuid)
            self.assertEqual(
                admin_finance.all_raffle_income, _game.price * raffle_count
            )
            user = Users.objects.get(openid="wx123")

            user_package = UserPackage.objects.filter(user_uuid=user.uuid).first()
            self.assertEqual(user_package.user_uuid, user.uuid)
            self.assertEqual(user_package.good_uuid, bee.uuid)
            self.assertEqual(user_package.count, raffle_count)

            wuxianshangRaffleRecord = WuxianshangRaffleRecord.objects.filter(
                user_uuid=user.uuid
            ).first()

            self.assertEqual(wuxianshangRaffleRecord.count, raffle_count)
            self.assertEqual(wuxianshangRaffleRecord.game_uuid, game.uuid)
            self.assertEqual(wuxianshangRaffleRecord.user_uuid, user.uuid)
            self.assertEqual(wuxianshangRaffleRecord.good_uuid, bee.uuid)

            r = self.wx_c.get(
                "/api/wuxianshang/raffle/",
                {"list": "1", "page": 1, "num": 50, "game_uuid": game.uuid},
                content_type="application/json",
            )
            d = json.loads(r.content)
            self.assertEqual(d[0]["game"]["count"], raffle_count)
            self.assertEqual(d[0]["good"]["count"], raffle_count)
            self.assertEqual(d[0]["good"]["uuid"], str(bee.uuid))

            # test exchange hunjing
            old_hunjing = user.hunjing

            r = self.wx_c.delete(
                "/api/wxuser/userpackage",
                {
                    "good_uuid": bee.uuid,
                    "count": 2,
                },
                content_type="application/json",
            )
            d = json.loads(r.content)
            self.assertEqual(d["user"]["hunjing"], old_hunjing + 2 * bee.price)
            self.assertEqual(d["goods"][0]["count"], raffle_count - 2)

    def test_raffle_duck_use_stored_money(self):
        _ = UserTest.create_a_user()
        game, goods = WuxianshangGameTest.create_a_game()
        duck = JuqiGood.objects.get(name="duck")

        # raffle
        raffle_count = 3

        with patch("wuxianshang.views.wxs_raffle") as _wxs_raffle:
            _wxs_raffle.return_value = {duck.uuid: raffle_count}
            r = self.wx_c.post(
                "/api/wuxianshang/raffle/",
                {
                    "pay_type": "stored_money",
                    "raffle_count": raffle_count,
                    "game_uuid": game.uuid,
                },
                content_type="application/json",
            )
            d = json.loads(r.content)

            self.assertEqual(r.status_code, status.HTTP_400_BAD_REQUEST)
            self.assertEqual(d["msg"], "server is busy, please retry raffle")

            user = Users.objects.get(openid="wx123")
            user_package = UserPackage.objects.filter(user_uuid=user.uuid).exists()

            self.assertEqual(user_package, False)


# python .\manage.py test wuxianshang.tests.WuxianshangArgsTest
class WuxianshangArgsTest(TestCase):
    def setUp(self):
        # Every test needs access to the request factory.
        self.c = Client()
        self.admin_user = {"user": "admin", "password": "admin123"}
        u = JuqiAdmin(**self.admin_user)
        u.save()

    def test_query_and_change_WuxianshangArgs(self):
        #  test err right
        r = self.c.get(
            "/api/wuxianshang/wuxianshangargs",
            content_type="application/json",
        )
        self.assertEqual(r.status_code, status.HTTP_400_BAD_REQUEST)

        # login
        r = self.c.post(
            "/api/admin/login",
            self.admin_user,
            content_type="application/json",
        )
        self.assertEqual(r.status_code, status.HTTP_200_OK)

        d = json.loads(r.content)
        self.assertEqual(len(self.c.session.get("login_token", "")), 64)
        self.assertEqual(d["code"], "0")

        # query after login
        r = self.c.get(
            "/api/wuxianshang/wuxianshangargs",
            content_type="application/json",
        )
        self.assertEqual(r.status_code, status.HTTP_200_OK)

        d = json.loads(r.content)
        self.assertEqual(float(d["wxs_min_sale_profit_percent"]), 0.1)
        self.assertEqual(d["wxs_min_sale_profit_window"], 30)
        self.assertEqual(d["wxs_user_lucky_window"], 30)

        params = {
            "wxs_min_sale_profit_percent": 0.11,
            "wxs_min_sale_profit_window": 31,
            "wxs_user_lucky_window": 32,
        }
        r = self.c.put(
            "/api/wuxianshang/wuxianshangargs",
            params,
            content_type="application/json",
        )
        self.assertEqual(r.status_code, status.HTTP_200_OK)

        d = json.loads(r.content)
        self.assertEqual(float(d["wxs_min_sale_profit_percent"]), 0.11)
        self.assertEqual(d["wxs_min_sale_profit_window"], 31)
        self.assertEqual(d["wxs_user_lucky_window"], 32)


class WuxianshangExtendBossRaffleTest(TestCase):
    def setUp(self):
        self.wx_c = Client(HTTP_X_WX_OPENID="wx123")

        self.admin_c = Client()

    # python .\manage.py test wuxianshang.tests.WuxianshangExtendBossRaffleTest.test_create_extendBoss_and_raffle
    def test_create_extendBoss_and_raffle(self):
        admin_login(self.admin_c)

        # 创建 boss 赏商品
        goods = [
            {
                "name": "wxs_good_1",
                "display_url": "img",
                "price": 10e2,
                "game_type": "无限赏",
                "ip_family": "一拳超人",
            },
            {
                "name": "wxs_good_2",
                "display_url": "img",
                "price": 100e2,
                "game_type": "无限赏",
                "ip_family": "一拳超人",
            },
            {
                "name": "wxs_good_3",
                "display_url": "img",
                "price": 1000e2,
                "game_type": "无限赏",
                "ip_family": "一拳超人",
            },
            {
                "name": "global_boss_good_1",
                "display_url": "img",
                "price": 10e2,
                "game_type": "boss赏",
                "ip_family": "一拳超人",
            },
            {
                "name": "global_boss_good_2",
                "display_url": "img",
                "price": 20e2,
                "game_type": "boss赏",
                "ip_family": "一拳超人",
            },
            {
                "name": "global_boss_good_3",
                "display_url": "img",
                "price": 30e2,
                "game_type": "boss赏",
                "ip_family": "一拳超人",
            },
            {
                "name": "each_boss_good_1",
                "display_url": "img",
                "price": 1e2,
                "game_type": "boss赏",
                "ip_family": "一拳超人",
            },
        ]
        good_name_map = {}
        wxs_goods = []
        boss_goods = []
        for good in goods:
            r = JuqiGoodTest.create_good(client=self.admin_c, good_info=good)
            self.assertEqual(r.status_code, status.HTTP_201_CREATED)

            d = json.loads(r.content)
            good_name_map[good["name"]] = d
            if d["game_type"] == "无限赏":
                wxs_goods.append(
                    {"good_uuid": d["uuid"], "good_weight": 1, "good_rarity": "传说款"}
                )
            elif d["game_type"] == "boss赏":
                is_global = int(str(d["name"]).startswith("global_"))
                boss_goods.append(
                    {
                        "good_uuid": d["uuid"],
                        "is_global": is_global,
                        "good_rarity": "传说款",
                        "count": 10,
                    }
                )

        game = {
            "name": "wxs_enable_boss",
            "display_url": "http://",
            "goods": wxs_goods,
            "extend_type_boss": True,
            "state": 1,
            "extend_boss": {
                "name": "boss赏1",
                "ticket_weight": 1,
                "draw_num": 100,
                "display_url": "img",
                "goods": boss_goods,
            },
        }

        # 创建 无限赏 盒子
        r = self.admin_c.post(
            "/api/wuxianshang/game",
            game,
            content_type="application/json",
        )
        self.assertEqual(r.status_code, status.HTTP_201_CREATED)

        _game = json.loads(r.content)

        self.assertEqual(_game["name"], game["name"])
        self.assertEqual(_game["display_url"], game["display_url"])

        pprint(_game)
        _extend_boss = _game["extend_boss"]
        _ticket_uuid = _extend_boss["ticket_uuid"]
        # boss 抽奖, 全部返回奖票
        _user = UserTest.create_a_user()
        with patch("wuxianshang.views.wxs_raffle") as _wxs_raffle:
            raffle_count = 101
            _wxs_raffle.return_value = {_ticket_uuid: raffle_count}
            params = {
                "raffle_count": raffle_count,
                "pay_type": "stored_money",
                "game_uuid": _game["uuid"],
            }
            r = self.wx_c.post(
                "/api/wuxianshang/raffle",
                params,
                content_type="application/json",
            )
            raffle_res = json.loads(r.content)
            # pprint(raffle_res)
            for u in Users.objects.filter(deleted=False):
                up = get_detail_UserPackage(u)
                pprint("用户背包")
                pprint(up)
                all_sum = calculate_UserPackage_sum_price(u.uuid)
                pprint("赏柜总价")
                pprint(all_sum)
                current_date_sum = calculate_UserPackage_sum_price_by_date(
                    u.uuid, datetime.datetime.now()
                )
                pprint("今天的赏柜总价")
                pprint(current_date_sum)

    # python .\manage.py test wuxianshang.tests.WuxianshangExtendBossRaffleTest.test_global_prize_raffle
    def test_global_prize_raffle(self):
        user_weight = {
            "zhangsan": 1,
            "xiaoliang": 4,
            "lisi": 2,
        }
        goods = {
            "bee": 12,
            "cat": 8,
            "dog": 4,
            "duck": 1,
        }
        good_count = sum(goods.values())

        prize_num = int(1e3)
        res = {g: {} for g in goods}
        for _ in range(prize_num):
            _once_good_count = 0
            _res = quanjushang_raffle(user_weight=user_weight, boss_goods_count=goods)
            for k in _res:
                for user_uuid in _res[k]:
                    _once_count = _res[k][user_uuid]
                    _once_good_count += _once_count
                    if user_uuid not in res[k]:
                        res[k][user_uuid] = _once_count
                    else:
                        res[k][user_uuid] += _once_count
            self.assertEqual(_once_good_count, good_count)
